package render;

import math.Maths;
import math.vec2f;
import math.vec3f;
import math.Vecmath;
import util.Bitmap;

public class Tri3 {

    public static final int nVerts = 3;
    public vec3f[] verts;
    public vec2f[] texs;
    public vec3f norm;
    public Bitmap tex;
    public int colorMod;
    public boolean clipped;

    public Tri3() {
        verts = new vec3f[nVerts];
        texs = new vec2f[nVerts];
    }

    public Tri3(vec3f[] vertices) {
        verts = new vec3f[nVerts];
        texs = new vec2f[nVerts];
        for (int i = 0; i < nVerts; i++) {
            verts[i] = new vec3f(vertices[i]);
        }
        clipped = false;
    }

    public Tri3(vec3f[] vertices, vec2f[] texCoords) {
        verts = new vec3f[nVerts];
        texs = new vec2f[nVerts];
        for (int i = 0; i < nVerts; i++) {
            verts[i] = new vec3f(vertices[i]);
            texs[i] = new vec2f(texCoords[i]);
        }
        clipped = false;
    }
    
    public Tri3(Tri3 tri) {
        this(tri.verts, tri.texs);
        norm = new vec3f(tri.norm);
        tex = tri.tex;
        colorMod = tri.colorMod;
        clipped = false;
    }
    
    public void colorModifier(int colorModifier) {
        colorMod = colorModifier;
    }
    
    public void texture(Bitmap texture) {
        tex = texture;
    }

    public void normalCalc() {
        norm = Vecmath.getSurfaceNormal(verts[0], verts[1], verts[2]);
    }
    
    public void normal(vec3f normal) {
        norm = new vec3f(normal);
    }

    public void normal(float nx, float ny, float nz) {
        normal(new vec3f(nx, ny, nz));
    }

    public void normal(double nx, double ny, double nz) {
        normal(new vec3f(nx, ny, nz));
    }

    public void vertex(int index, float vx, float vy, float vz) {
        vertex(index, new vec3f(vx, vy, vz));
    }
    
    public void vertex(int index, double vx, double vy, double vz) {
        vertex(index, (float)vx, (float)vy, (float)vz);
    }
    
    public void vertex(int index, vec3f vert) {
        verts[index] = new vec3f(vert);
    }

    public void texCoord(int index, float s, float t) {
        texCoord(index, new vec2f(s, t));
    }
    
    public void texCoord(int index, double s, double t) {
        texCoord(index, new vec2f(s, t));
    }
    
    public void texCoord(int index, vec2f texCoord) {
        texs[index] = new vec2f(texCoord);
    }
    
    public void rotateDeg(float pitch, float yaw, float roll, float xpos, float ypos, float zpos) {
        float rollRad = Maths.toRadians(roll);
        float yawRad = Maths.toRadians(yaw);
        float pitchRad = Maths.toRadians(pitch);
        rotateRad(pitchRad, yawRad, rollRad, xpos, ypos, zpos);
    }
    
    public void rotateDeg(vec3f anglesDeg, float xpos, float ypos, float zpos) {
        rotateDeg(anglesDeg.x, anglesDeg.y, anglesDeg.z, xpos, ypos, zpos);
    }
    
    public void rotateRad(vec3f anglesRad, float xpos, float ypos, float zpos) {
        rotateRad(anglesRad.x, anglesRad.y, anglesRad.z, xpos, ypos, zpos);
    }
    
    public void rotateRad(float pitch, float yaw, float roll, float xpos, float ypos, float zpos) {
        vec3f trans = new vec3f(xpos, ypos, zpos);
        vec3f transInvert = trans.getInverted();
        for (int i=0; i < verts.length; i++) {
            vec3f vert = Vecmath.add(verts[i], transInvert);
            if (roll != 0)
                vert = Vecmath.rotate(vert, 0, 0, 1, roll);
            if (yaw != 0)
                vert = Vecmath.rotate(vert, 0, 1, 0, yaw);
            if (pitch != 0)
                vert = Vecmath.rotate(vert, 1, 0, 0, pitch);
            verts[i] = Vecmath.add(vert, trans);
        }
        vec3f vert = Vecmath.add(norm, transInvert);
        vert = Vecmath.rotate(vert, 0, 0, 1, roll);
        vert = Vecmath.rotate(vert, 0, 1, 0, yaw);
        vert = Vecmath.rotate(vert, 1, 0, 0, pitch);
        norm = Vecmath.add(vert, trans);
    }
    
    public void translate(float dx, float dy, float dz) {
        verts[0].add(dx, dy, dz);
        verts[1].add(dx, dy, dz);
        verts[2].add(dx, dy, dz);
    }
    
    public void translate(vec3f translate) {
        verts[0].add(translate.x, translate.y, translate.z);
        verts[1].add(translate.x, translate.y, translate.z);
        verts[2].add(translate.x, translate.y, translate.z);
    }
    
    public boolean hasTexCoords() {
        return (texs[0] != null && texs[1] != null && texs[2] != null);
    }
    
    public String toString() {
        String s = "";
        for (int i = 0; i < nVerts; i++) {
            s += "xyz: " + verts[i].toString() + "\n";
            s += "   st: " + texs[i].toString() + "\n";
            s += "   norm: " + norm.toString() + "\n";
        }
        return s;
    }
    
    public void checkBounds() {
        boolean aboveX = (verts[0].x >= -1.0f && verts[1].x >= -1.0f && verts[2].x >= -1.0f);
        boolean belowX = (verts[0].x <= 1.0f && verts[1].x <= 1.0f && verts[2].x <= 1.0f);
        boolean aboveY = (verts[0].y >= -1.0f && verts[1].y >= -1.0f && verts[2].y >= -1.0f);
        boolean belowY = (verts[0].y <= 1.0f && verts[1].y <= 1.0f && verts[2].y <= 1.0f);
        boolean aboveZ = (verts[0].z >= -1.0f && verts[1].z >= -1.0f && verts[2].z >= -1.0f);
        boolean belowZ = (verts[0].z <= 1.0f && verts[1].z <= 1.0f && verts[2].z <= 1.0f);
        clipped = !(aboveX && belowX && aboveY && belowY && aboveZ && belowZ);
    }
    
    public void raster(Rasterizer _raster) {
        if (!clipped) {
            if (tex != null) {
                _raster.triBitmapf(
                        verts[0].x, verts[0].y, verts[0].z, texs[0].x, texs[0].y, 
                        verts[1].x, verts[1].y, verts[1].z, texs[1].x, texs[1].y, 
                        verts[2].x, verts[2].y, verts[2].z, texs[2].x, texs[2].y, 
                        tex
                        );
            } else {
                _raster.triFill(
                        (int)(verts[0].x), (int)(verts[0].y), verts[0].z, 
                        (int)(verts[1].x), (int)(verts[1].y), verts[1].z, 
                        (int)(verts[2].x), (int)(verts[2].y), verts[2].z, 
                        colorMod
                        );
//                _raster.triGouraud(
//                        (int)(verts[0].x), (int)(verts[0].y), verts[0].z, 
//                        (int)(verts[1].x), (int)(verts[1].y), verts[1].z, 
//                        (int)(verts[2].x), (int)(verts[2].y), verts[2].z, 
////                        Color.YELLOW,
////                        Color.CYAN,
////                        Color.MAGENTA
//                        Color.RED,
//                        Color.GREEN,
//                        Color.BLUE
//                        );
            }
        }
    }

}
